using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace PonGun
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        public PostProcessingManager ppm;
        public CrepuscularRays rays;
        Vector2 rayStartingPos = Vector2.One * .5f;

        public static bool Debug = false;
        public static Vector2 topNormal = new Vector2(0, 1);
        public static Vector2 leftNormal = new Vector2(1, 0);
        public static Vector2 rightNormal = new Vector2(-1, 0);
        public static Vector2 botNormal = new Vector2(0, -1);

        public static Random rnd = new Random(DateTime.Now.Millisecond);
        public static Rectangle RenderArea { get { return new Rectangle(0, 0, 960, 600); } }
        public static Vector2 RenderAreaCenter { get { return new Vector2(480, 300); } }
        public Vector2 vpCenter { get { return new Vector2(GraphicsDevice.Viewport.Width / 2, GraphicsDevice.Viewport.Height / 2); } }
        public static int ScreenMargin = 4;
        public static float ScreenRotation = 0;
        static SpriteEffects _ScreenSpriteEffect = SpriteEffects.None;
        public static SpriteEffects ScreenSpriteEffect
        {
            get { return _ScreenSpriteEffect; }
            set
            {
                if (value != SpriteEffects.None && value != _ScreenSpriteEffect)
                    ScreenEffectStart = DateTime.Now.TimeOfDay;

                _ScreenSpriteEffect = value;
            }
        }

        public List<Pickup> PickupsInPlay = new List<Pickup>();
        public List<Pickup> pickupstoDie = new List<Pickup>();

        public string Difficulty = "Easy";

        public int Level = 1;
        public int Players = 0;

        bool _renderMist;
        public bool RenderMist
        {
            get { return _renderMist; }
            set
            {
                if (value)
                    ScreenEffectStart = DateTime.Now.TimeOfDay;

                _renderMist = value;
            }
        }

        bool _RenderNova = false;
        public bool RenderNova
        {
            get { return _RenderNova; }
            set
            {
                if(value && value != _RenderNova)
                    Content.Load<SoundEffect>("Audio/SFX/nova").Play();

                if (value)
                {
                    GetRandomFlare();
                }

                _RenderNova = value;
            }
        }
        public static Vector2 ScreenOrigin = new Vector2(RenderArea.Width / 2, RenderArea.Height / 2);

        public static TimeSpan ScreenEffectStart = TimeSpan.Zero;
        public static TimeSpan ScreenEffectDuration = new TimeSpan(0, 0, 0, 15, 0);
        public static bool ScreenEffectOver { get { return (ScreenEffectDuration - (DateTime.Now.TimeOfDay - ScreenEffectStart) < TimeSpan.Zero); } }
        public static TimeSpan ScreenEffectTimeLeft { get { return ScreenEffectDuration - (DateTime.Now.TimeOfDay - ScreenEffectStart); } }
        
        static bool _ScreenRotating;
        public static bool ScreenRotating 
        { 
            get { return _ScreenRotating; } 
            set 
            { 
                _ScreenRotating = value;

                if (!_ScreenRotating)
                    ScreenRotation = 0;
                else
                    ScreenEffectStart = DateTime.Now.TimeOfDay;
            }
        }


        public static Color Player1Color = Color.Red;
        public static Color Player2Color = Color.Blue;
        
        GraphicsDeviceManager graphics;
        public SpriteBatch spriteBatch;

        public RenderTarget2D finalRT;
        public RenderTarget2D sceneRT;
        public RenderTarget2D rayShadows;

        public List<Bat> Bats = new List<Bat>();
        public List<Ball> Balls = new List<Ball>();

        #region Controlers
        public KeyboardState thisKB;
        public KeyboardState lastKB;

        public MouseState thisMS;
        public MouseState lastMS;

        public GamePadState thisP1GP;
        public GamePadState lastP1GP;

        public GamePadState thisP2GP;
        public GamePadState lastP2GP;

        CollisionManager collisionManager;

        public List<Block> Blocks = new List<Block>();

        public List<City> Cities = new List<City>();

        public List<PopMsg> PopUpMessages = new List<PopMsg>();

        public ParticleEmitterBase testEmitter;

        public Field field;

        public bool IsKeyPressed(Keys key)
        {
            return thisKB.IsKeyUp(key) && lastKB.IsKeyDown(key);
        }

        public bool IsKeyDown(Keys key)
        {
            return thisKB.IsKeyDown(key);
        }

        public bool IsLeftMouseClicked()
        {
            return thisMS.LeftButton == ButtonState.Released && lastMS.LeftButton == ButtonState.Pressed;
        }

        public bool IsLeftMouseDown()
        {
            return thisMS.LeftButton == ButtonState.Pressed;
        }

        public bool IsP1RightTriggerPulled
        {
            get { return (thisP1GP.Triggers.Right == 0 && lastP1GP.Triggers.Right > 0); }
        }
        public bool IsP1LeftTriggerPulled
        {
            get { return (thisP1GP.Triggers.Left == 0 && lastP1GP.Triggers.Left > 0); }
        }

        public bool IsP2RightTriggerPulled
        {
            get { return (thisP2GP.Triggers.Right == 0 && thisP2GP.Triggers.Right > 0); }
        }
        public bool IsP2LeftTriggerPulled
        {
            get { return (thisP2GP.Triggers.Left == 0 && thisP2GP.Triggers.Left > 0); }
        }

        GSM gsm;

        #endregion

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            ppm = new PostProcessingManager(this);

            rays = new CrepuscularRays(this, Vector2.One * .5f, "Textures/flare", 1, .78f, .98f, .25f, 1f);
            ppm.AddEffect(rays);

            this.Window.AllowUserResizing = true;
            
            graphics.PreferredBackBufferWidth = 960;
            graphics.PreferredBackBufferHeight = 600;

            collisionManager = new CollisionManager(this) { Debug = Game1.Debug };

            ReSetGame();           
        }

        void GetRandomFlare()
        {
            switch (rnd.Next(0, 7))
            {
                case 0:
                    rays.lightTexture = Content.Load<Texture2D>("Textures/flare");
                    break;
                case 1:
                    rays.lightTexture = Content.Load<Texture2D>("Textures/flare2");
                    break;
                case 2:
                    rays.lightTexture = Content.Load<Texture2D>("Textures/flare3");
                    break;
                case 3:
                    rays.lightTexture = Content.Load<Texture2D>("Textures/flare4");
                    break;
                case 4:
                    rays.lightTexture = Content.Load<Texture2D>("Textures/flare5");
                    break;
                case 5:
                    rays.lightTexture = Content.Load<Texture2D>("Textures/flare6");
                    break;
                case 6:
                    rays.lightTexture = Content.Load<Texture2D>("Textures/flare7");
                    break;
            }
            //rays.lightTexture = Content.Load<Texture2D>("Textures/flare7");
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            base.Initialize();



            //List<DisplayMode> dms = this.GraphicsDevice.Adapter.SupportedDisplayModes.Where(displayMode => displayMode.AspectRatio == this.GraphicsDevice.DisplayMode.AspectRatio).ToList();
            

            finalRT = new RenderTarget2D(GraphicsDevice, RenderArea.Width, RenderArea.Height);
            sceneRT = new RenderTarget2D(GraphicsDevice, RenderArea.Width, RenderArea.Height);
            rayShadows = new RenderTarget2D(GraphicsDevice, RenderArea.Width, RenderArea.Height);

            // Pre load all the assets we need.
            Content.Load<Texture2D>("Textures/flare");
            Content.Load<Texture2D>("Textures/flare2");
            Content.Load<Texture2D>("Textures/flare3");
            Content.Load<Texture2D>("Textures/flare4");
            Content.Load<Texture2D>("Textures/flare5");
            Content.Load<Texture2D>("Textures/flare6");
            Content.Load<Texture2D>("Textures/flare7");

            // load the sound
            Content.Load<SoundEffect>("Audio/Music/PonGunInGameMusic2");
            Content.Load<SoundEffect>("Audio/Music/PonGunMenuMusic");

            Content.Load<SoundEffect>("Audio/SFX/batpupickup");
            Content.Load<SoundEffect>("Audio/SFX/bhbk");
            Content.Load<SoundEffect>("Audio/SFX/bhbl");
            Content.Load<SoundEffect>("Audio/SFX/bhblt");
            Content.Load<SoundEffect>("Audio/SFX/bhbt");
            Content.Load<SoundEffect>("Audio/SFX/bhcy");
            Content.Load<SoundEffect>("Audio/SFX/bhpu");
            Content.Load<SoundEffect>("Audio/SFX/cityHit");
            Content.Load<SoundEffect>("Audio/SFX/gameOver");
            Content.Load<SoundEffect>("Audio/SFX/healCity");
            Content.Load<SoundEffect>("Audio/SFX/laser-01");
            Content.Load<SoundEffect>("Audio/SFX/laser-02");
            Content.Load<SoundEffect>("Audio/SFX/levelUp");
            Content.Load<SoundEffect>("Audio/SFX/nova");
            Content.Load<SoundEffect>("Audio/SFX/resCity");
            Content.Load<SoundEffect>("Audio/SFX/shieldUp");


            gsm = new GSM(this);
            gsm.AddScreen(new TitleScreen(this, gsm) { Name = "TitleScreen", Asset = "Textures/Screens/title" });
            gsm.AddScreen(new MenuScreen(this, gsm) { Name = "MenuScreen", Asset = "Textures/Screens/mainmenu" });
            gsm.AddScreen(new OptionsScreen(this, gsm) { Name = "OptionsScreen", Asset = "Textures/Screens/options" });
            gsm.AddScreen(new GameScreen(this, gsm) { Name = "GameScreen" });

            gsm.CurrentScreen = "TitleScreen";

            GetRandomFlare();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            Services.AddService(typeof(SpriteBatch), spriteBatch);

            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            thisKB = Keyboard.GetState();
            thisMS = Mouse.GetState();
            thisP1GP = GamePad.GetState(PlayerIndex.One);
            thisP2GP = GamePad.GetState(PlayerIndex.Two);

            // Allows the game to exit
            //if (IsKeyPressed(Keys.Escape))
            //    this.Exit();

            //if (IsKeyPressed(Keys.F1))
            //    Debug = !Debug;

            //if (IsKeyPressed(Keys.F2))
            //    ScreenRotating = true;

            //if (IsKeyPressed(Keys.F4))
            //    ClearExcessBalls();

            //if (IsKeyPressed(Keys.F2))
            //{
            //    if (Cities[0].Destroyed)
            //        Cities[0].ReserectCity();
            //    else
            //        Cities[0].DestroyCity();
            //}

            //if (IsKeyPressed(Keys.F3))
            //    RenderNova = !RenderNova;

            if (Balls[Balls.Count - 1].Speed == 0)
            {
                if (IsKeyDown(Keys.Up))
                    Balls[0].Translate(new Vector2(0, -1), .5f);

                if (IsKeyDown(Keys.Down))
                    Balls[0].Translate(new Vector2(0, 1), .5f);

                if (IsKeyDown(Keys.Left))
                    Balls[0].Translate(new Vector2(-1, 0), .5f);

                if (IsKeyDown(Keys.Right))
                    Balls[0].Translate(new Vector2(1, 0), .5f);
            }

            // Update...
            gsm.Update(gameTime);

            if (RenderNova)
            {
                rays.lightSource = Balls[0].Position / new Vector2(RenderArea.Width, RenderArea.Height);
            }


            base.Update(gameTime);

            foreach (Pickup ptd in pickupstoDie)
                PickupsInPlay.Remove(ptd);

            pickupstoDie.Clear();

            lastKB = thisKB;
            lastMS = thisMS;
            lastP1GP = thisP1GP;
            lastP2GP = thisP2GP;
        }


        public bool RenderAllBalck = false;

        public void MultiBall()
        {
            int bcnt = Balls.Count;
            if (bcnt < 32)
            {
                Vector2 newVel = Vector2.Zero;

                for (int b = 0; b < bcnt; b++)
                {
                    if (Balls[b].Velocity.Y < 0)
                        newVel = Vector2.Reflect(Balls[b].Velocity, Game1.topNormal);
                    else
                        newVel = Vector2.Reflect(Balls[b].Velocity, Game1.botNormal);

                    Balls.Add(new Ball(this) { Position = Balls[b].Position + (newVel * 8), Velocity = newVel });
                }
            }
        }

        public void ClearExcessBalls()
        {
            int bcnt = Balls.Count;
            if (bcnt > 1)
            {
                for (int b = bcnt - 1; b >= 1; b--)
                {
                    Balls[b].KillBall();
                    Balls.RemoveAt(b);
                }
            }
        }

        public void RemoveBall(Ball ball = null)
        {
            int bcnt = Balls.Count;
            if (bcnt > 1)
            {
                if (ball == null)
                    ball = Balls[Balls.Count - 1];

                Balls.Remove(ball);
                ball.KillBall();
            }  
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            if (RenderNova)
            {
                RenderAllBalck = true;
                GraphicsDevice.SetRenderTarget(rayShadows);
                // Render it all again for the shadow map..
                GraphicsDevice.Clear(Color.White);

                spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque);
                RenderScene(gameTime);
                spriteBatch.End();

                GraphicsDevice.SetRenderTarget(null);

                // Apply the post processing manger (just the rays in this one)
                ppm.Draw(gameTime, rayShadows);
                RenderAllBalck = false;
            }

            GraphicsDevice.SetRenderTarget(sceneRT);
            GraphicsDevice.Clear(Color.Black);

            // Example Draw, put a red square in the center of the render area.
            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.NonPremultiplied);
            
            gsm.Draw(gameTime);

            // clean em out
            int popcnt = PopUpMessages.Count;
            for (int m = popcnt - 1; m >= 0; m--)
            {
                if (PopUpMessages[m].opacity <= 0)
                    PopUpMessages.RemoveAt(m);
            }

            if (Game1.Debug)
            {
                foreach (Block testBlock in Blocks)
                    if (testBlock.overlapRect != Rectangle.Empty)
                        spriteBatch.Draw(testBlock.Texture2D, testBlock.overlapRect, new Color(1f, 0, 0, .25f));
            }

            spriteBatch.End();

            GraphicsDevice.SetRenderTarget(null);

            if (RenderNova)
            {
                GraphicsDevice.SetRenderTarget(finalRT);

                GraphicsDevice.Clear(Color.Black);

                spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Additive);
                spriteBatch.Draw(ppm.Scene, Game1.RenderArea, Color.White);
                spriteBatch.Draw(sceneRT, Game1.RenderArea, Color.White);
                spriteBatch.End();

                GraphicsDevice.SetRenderTarget(null);
            }

            GraphicsDevice.Clear(Color.Black);

            if (Game1.ScreenRotating)
            {
                spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Additive);
                gsm.DrawStarsVP(gameTime);
                DrawMistViewPort(Color.Blue, Color.Red);
                spriteBatch.End();
            }
            
            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque);            

            Rectangle finalScreenRect = new Rectangle(GraphicsDevice.Viewport.TitleSafeArea.Width / 2, GraphicsDevice.Viewport.TitleSafeArea.Height / 2, GraphicsDevice.Viewport.TitleSafeArea.Width, GraphicsDevice.Viewport.TitleSafeArea.Height);
            if (RenderNova)
                spriteBatch.Draw(finalRT, finalScreenRect, null, Color.White, Game1.ScreenRotation, Game1.ScreenOrigin, Game1.ScreenSpriteEffect, 0);
            else
                spriteBatch.Draw(sceneRT, finalScreenRect, null, Color.White, Game1.ScreenRotation, Game1.ScreenOrigin, Game1.ScreenSpriteEffect, 0);

            spriteBatch.End();

            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
            if (Game1.ScreenRotating)
                Game1.ScreenRotation += .01f;

            if (Game1.ScreenEffectOver)
            {
                // Cancel spin and flip
                Game1.ScreenRotating = false;
                Game1.ScreenSpriteEffect = SpriteEffects.None;
                RenderMist = false;
            }
            else
            {
                string tickMsg = string.Format("{0:ss}", Game1.ScreenEffectTimeLeft);
                if (tickMsg != lastTickMsg)
                {
                    Bats[0].Score += 10 * Level;
                    Bats[1].Score += 10 * Level;
                    lastTickMsg = tickMsg;
                    // Play sound..
                }               

                Vector2 effectCntPos = vpCenter - (Content.Load<SpriteFont>("Fonts/EffecTCounterFont").MeasureString(tickMsg) / 2);
                spriteBatch.DrawString(Content.Load<SpriteFont>("Fonts/EffecTCounterFont"), tickMsg, effectCntPos + new Vector2(-2, 2), Color.Black);
                spriteBatch.DrawString(Content.Load<SpriteFont>("Fonts/EffecTCounterFont"), tickMsg, effectCntPos, Color.Red);
            }

            spriteBatch.End();
        }

        public void ReSetGame()
        {
            Blocks.Clear();

            ScreenEffectStart = DateTime.Now.TimeOfDay - ScreenEffectDuration;
            Game1.ScreenRotating = false;
            Game1.ScreenSpriteEffect = SpriteEffects.None;
            RenderMist = false;
            RenderNova = false;

            collisionManager.ReSet();

            Bats.Clear();
            Bats.Add(new Bat(this, PlayerIndex.One));
            Bats[Bats.Count - 1].Position = new Vector2(0, 200);

            Bats.Add(new Bat(this, PlayerIndex.Two));
            Bats[Bats.Count - 1].Position = new Vector2(0, 300);

            float x, y, r, g, b;
            Color c;
            Block blk;
            
            switch (Difficulty)
            {
                case "Easy":
                    Level = 1;
                    // terrain
                    //Blocks.Add(new Block(this) { Asset = "Textures/White", Color = Color.SteelBlue, Width = 128, Height = 32, Position = RenderAreaCenter - new Vector2(0, 32) });
                    //Blocks.Add(new Block(this) { Asset = "Textures/White", Color = Color.SteelBlue, Width = 32, Height = 128, Position = RenderAreaCenter - new Vector2(0, -128) });
                    
                    // Random placement of 32x32 blocks.
                    for (int bl = 0; bl < 10; bl++)
                    {
                        x = MathHelper.Lerp(256, RenderArea.Width - 256, (float)rnd.NextDouble());
                        y = MathHelper.Lerp(64, RenderArea.Height - 64, (float)rnd.NextDouble());

                        r = MathHelper.Lerp(.5f, 1f, (float)rnd.NextDouble());
                        g = MathHelper.Lerp(.5f, 1f, (float)rnd.NextDouble());
                        b = MathHelper.Lerp(.5f, 1f, (float)rnd.NextDouble());


                        blk = new Block(this)
                        {
                            Asset = "Textures/White", 
                            Color = new Color(r,g,b,1f),
                            Width = 32, 
                            Height = 32, 
                            Position = new Vector2(x,y)
                        };

                        Blocks.Add(blk);
                    }

                    // guns
                    AddGun(Bats[0]);
                    AddGun(Bats[0]);

                    IncreaseRateOfFire(Bats[0]);

                    if (Players > 1)
                    {
                        AddGun(Bats[1]);
                        AddGun(Bats[1]);

                        IncreaseRateOfFire(Bats[1]);
                    }
                    break;
                case "Normal":
                    Level = 4;
                    // terrain
                    
                    for (int bl = 0; bl < 20; bl++)
                    {
                        x = MathHelper.Lerp(256, RenderArea.Width - 256, (float)rnd.NextDouble());
                        y = MathHelper.Lerp(64, RenderArea.Height - 64, (float)rnd.NextDouble());

                        r = MathHelper.Lerp(.5f, 1f, (float)rnd.NextDouble());
                        g = MathHelper.Lerp(.5f, 1f, (float)rnd.NextDouble());
                        b = MathHelper.Lerp(.5f, 1f, (float)rnd.NextDouble());


                        blk = new Block(this)
                        {
                            Asset = "Textures/White", 
                            Color = new Color(r,g,b,1f),
                            Width = 32, 
                            Height = 32, 
                            Position = new Vector2(x,y)
                        };

                        Blocks.Add(blk);
                    }
                    // guns
                    // None..
                    break;
                case "Hard":
                    Level = 8;
                    // terrain
                    for (int bl = 0; bl < 30; bl++)
                    {
                        x = MathHelper.Lerp(256, RenderArea.Width - 256, (float)rnd.NextDouble());
                        y = MathHelper.Lerp(64, RenderArea.Height - 64, (float)rnd.NextDouble());

                        r = MathHelper.Lerp(.5f, 1f, (float)rnd.NextDouble());
                        g = MathHelper.Lerp(.5f, 1f, (float)rnd.NextDouble());
                        b = MathHelper.Lerp(.5f, 1f, (float)rnd.NextDouble());


                        blk = new Block(this)
                        {
                            Asset = "Textures/White",
                            Color = new Color(r, g, b, 1f),
                            Width = 32,
                            Height = 32,
                            Position = new Vector2(x, y)
                        };

                        Blocks.Add(blk);
                    }

                    // guns
                    if (Players == 1)
                    {
                        AddGun(Bats[1]);
                        AddGun(Bats[1]);
                        IncreaseRateOfFire(Bats[1]);
                    }
                    break;
            }            
            

            Balls.Clear();
            Balls.Add(new Ball(this));
            Balls[Balls.Count - 1].Position = RenderAreaCenter;
            Balls[Balls.Count - 1].Speed = Level;
            Balls[Balls.Count - 1].SetInitialVelocity(Balls[Balls.Count - 1].Speed);

            Cities.Clear();
            Cities.Add(new City(this, PlayerIndex.One, CityNos.One));
            Cities.Add(new City(this, PlayerIndex.One, CityNos.Two));
            Cities.Add(new City(this, PlayerIndex.One, CityNos.Three));
            Cities.Add(new City(this, PlayerIndex.One, CityNos.Four));

            Cities.Add(new City(this, PlayerIndex.Two, CityNos.One));
            Cities.Add(new City(this, PlayerIndex.Two, CityNos.Two));
            Cities.Add(new City(this, PlayerIndex.Two, CityNos.Three));
            Cities.Add(new City(this, PlayerIndex.Two, CityNos.Four));

            field = new Field(this);

            testEmitter = new ParticleEmitterBase(this);
        }

        public void IncreaseRateOfFire(Bat bat)
        {
            // Up the rate of fire on all guns
            foreach (BatGun gun in bat.Guns)
            {
                int rf = (int)gun.rateOfFire.TotalMilliseconds / 2;
                if (rf < 100)
                    rf = 100;

                gun.rateOfFire = new TimeSpan(0, 0, 0, 0, rf);
            }
        }

        public bool AddGun(Bat bat)
        {
            if (bat.Guns.Count < 3)
            {
                if (bat.Guns.SingleOrDefault(entity => entity.gunPosition == GunPos.Top) == null)
                {
                    switch (bat.Player)
                    {
                        case PlayerIndex.One:
                            bat.Guns.Add(new BatGun(this, bat, "Textures/BatGun/TopRBasic", GunPos.Top) { rateOfFire = new TimeSpan(0, 0, 0, 1, bat.rndTimeOffset + 50) });
                            break;
                        case PlayerIndex.Two:
                            bat.Guns.Add(new BatGun(this, bat, "Textures/BatGun/TopLBasic", GunPos.Top) { rateOfFire = new TimeSpan(0, 0, 0, 1, bat.rndTimeOffset + 50) });
                            break;
                    }
                }
                else
                {
                    if (bat.Guns.SingleOrDefault(entity => entity.gunPosition == GunPos.Bottom) == null)
                    {
                        switch (bat.Player)
                        {
                            case PlayerIndex.One:
                                bat.Guns.Add(new BatGun(this, bat, "Textures/BatGun/BotRBasic", GunPos.Bottom) { rateOfFire = new TimeSpan(0, 0, 0, 1, bat.rndTimeOffset) });
                                break;
                            case PlayerIndex.Two:
                                bat.Guns.Add(new BatGun(this, bat, "Textures/BatGun/BotLBasic", GunPos.Bottom) { rateOfFire = new TimeSpan(0, 0, 0, 1, bat.rndTimeOffset) });
                                break;
                        }
                    }                    
                    else
                    {
                        if (bat.Guns.SingleOrDefault(entity => entity.gunPosition == GunPos.Center) == null)
                        {
                            switch (bat.Player)
                            {
                                case PlayerIndex.One:
                                    bat.Guns.Add(new BatGun(this, bat, "Textures/BatGun/MidRBasic", GunPos.Center) { rateOfFire = new TimeSpan(0, 0, 0, 1, bat.rndTimeOffset + 150) });
                                    break;
                                case PlayerIndex.Two:
                                    bat.Guns.Add(new BatGun(this, bat, "Textures/BatGun/MidLBasic", GunPos.Center) { rateOfFire = new TimeSpan(0, 0, 0, 1, bat.rndTimeOffset + 150) });
                                    break;
                            }
                        }   
                    }
                }
                return true;
            }
            return false;
        }

        public void RenderScene(GameTime gameTime)
        {
            foreach (Block testBlock in Blocks)
                testBlock.Draw(gameTime);

            foreach (City city in Cities)
            {
                if (!city.Destroyed)
                    city.Draw(gameTime);
            }

            foreach (Bat bat in Bats)
                bat.Draw(gameTime);

            foreach (Ball ball in Balls)
                ball.Draw(gameTime);

            foreach (Bat bat in Bats)
            {
                if (bat.Guns.Count > 0)
                    bat.DrawGunData();
            }

            testEmitter.Draw(gameTime);

            if (RenderMist)
                DrawMist(Color.White, Color.White);

            string HUDString = string.Empty;
            Vector2 pos = Vector2.Zero;
            Vector2 shadow = new Vector2(-2, 2);

            HUDString = string.Format("Score: {0:000000}\nCities : {1:0}", Bats.SingleOrDefault(entity => entity.Player == PlayerIndex.One).Score, Cities.Count(entity => entity.Player == PlayerIndex.One && !entity.Destroyed));
            pos = new Vector2((Game1.RenderAreaCenter.X + (Game1.RenderArea.Width / 4)) - Content.Load<SpriteFont>("Fonts/Citydatafont").MeasureString(HUDString).X - 16, 8);
            spriteBatch.DrawString(Content.Load<SpriteFont>("Fonts/Citydatafont"), HUDString, pos + shadow, Color.Black);
            spriteBatch.DrawString(Content.Load<SpriteFont>("Fonts/Citydatafont"), HUDString, pos, Game1.Player1Color);

            HUDString = string.Format("Score: {0:000000}\nCities : {1:0}", Bats.SingleOrDefault(entity => entity.Player == PlayerIndex.Two).Score, Cities.Count(entity => entity.Player == PlayerIndex.Two && !entity.Destroyed));
            pos = new Vector2((Game1.RenderAreaCenter.X - (Game1.RenderArea.Width / 4)) - Content.Load<SpriteFont>("Fonts/Citydatafont").MeasureString(HUDString).X - 16, 8);

            spriteBatch.DrawString(Content.Load<SpriteFont>("Fonts/Citydatafont"), HUDString, pos + shadow, Color.Black);
            spriteBatch.DrawString(Content.Load<SpriteFont>("Fonts/Citydatafont"), HUDString, pos, Game1.Player2Color);

            HUDString = string.Format("LEVEL : {0:000}", Level);
            pos = new Vector2(Game1.RenderAreaCenter.X - (Content.Load<SpriteFont>("Fonts/Citydatafont").MeasureString(HUDString).X / 2), Game1.RenderArea.Height - Content.Load<SpriteFont>("Fonts/Citydatafont").MeasureString(HUDString).Y - 16);

            spriteBatch.DrawString(Content.Load<SpriteFont>("Fonts/Citydatafont"), HUDString, pos + shadow, Color.Black);
            spriteBatch.DrawString(Content.Load<SpriteFont>("Fonts/Citydatafont"), HUDString, pos, Color.Purple);

            collisionManager.Draw(gameTime);

            int popcnt = PopUpMessages.Count;
            SpriteFont msgFont = Content.Load<SpriteFont>("Fonts/popupMsg");
            Rectangle renderRect;
            PopMsg msg;
            Vector2 msgSize;
            for (int m = 0; m < popcnt; m++)
            {
                msg = PopUpMessages[m];

                if (msg.FadeOut)
                {
                    msg.opacity -= msg.fade;
                    if (msg.opacity <= 0)
                        msg.opacity = 0;
                }
                msgSize = msgFont.MeasureString(msg.message);

                renderRect = new Rectangle((int)msg.position.X - 4, (int)msg.position.Y - 4, 8 + (int)msgSize.X, 8 + (int)msgSize.Y);
                // Draw bG
                spriteBatch.Draw(Content.Load<Texture2D>("Textures/halfshade"), renderRect, new Color(1, 1, 1, msg.opacity));
                spriteBatch.DrawString(msgFont, msg.message, msg.position + new Vector2(-2, 2), new Color(0, 0, 0, (byte)(255 * msg.opacity)));
                spriteBatch.DrawString(msgFont, msg.message, msg.position, new Color(msg.Color.R, msg.Color.G, msg.Color.B, (byte)(255 * msg.opacity)));
            }
        }

        float mistBGX;
        float mistFGX;
        float bgSpeed = 1;
        float fgSpeed = 1;
        public void DrawMist(Color bgColor, Color fgColor)
        {
            Rectangle bgRect = new Rectangle((int)(mistBGX += bgSpeed), 0, RenderArea.Width, RenderArea.Height);
            Rectangle bg2Rect = new Rectangle((int)(mistBGX) - RenderArea.Width, 0, RenderArea.Width, RenderArea.Height);

            Rectangle fgRect = new Rectangle((int)(mistFGX -= fgSpeed), 0, RenderArea.Width, RenderArea.Height);
            Rectangle fg2Rect = new Rectangle((int)(mistFGX) + RenderArea.Width, 0, RenderArea.Width, RenderArea.Height);

           
            spriteBatch.Draw(Content.Load<Texture2D>("Textures/mist1"), bgRect, bgColor);
            spriteBatch.Draw(Content.Load<Texture2D>("Textures/mist1"), bg2Rect, bgColor);

            spriteBatch.Draw(Content.Load<Texture2D>("Textures/mist2"), fgRect, fgColor);
            spriteBatch.Draw(Content.Load<Texture2D>("Textures/mist2"), fg2Rect, fgColor);
           

            if (mistBGX >= RenderArea.Width)
                mistBGX = 0;

            if (mistFGX <= -RenderArea.Width)
                mistFGX = 0;
        }

        public void DrawMistViewPort(Color bgColor, Color fgColor)
        {
            Rectangle bgRect = new Rectangle((int)(mistBGX += bgSpeed), 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);
            Rectangle bg2Rect = new Rectangle((int)(mistBGX) - GraphicsDevice.Viewport.Width, 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);

            Rectangle fgRect = new Rectangle((int)(mistFGX -= fgSpeed), 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);
            Rectangle fg2Rect = new Rectangle((int)(mistFGX) + GraphicsDevice.Viewport.Width, 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);


            spriteBatch.Draw(Content.Load<Texture2D>("Textures/mist1"), bgRect, bgColor);
            spriteBatch.Draw(Content.Load<Texture2D>("Textures/mist1"), bg2Rect, bgColor);

            spriteBatch.Draw(Content.Load<Texture2D>("Textures/mist2"), fgRect, fgColor);
            spriteBatch.Draw(Content.Load<Texture2D>("Textures/mist2"), fg2Rect, fgColor);


            if (mistBGX >= GraphicsDevice.Viewport.Width)
                mistBGX = 0;

            if (mistFGX <= -GraphicsDevice.Viewport.Width)
                mistFGX = 0;
        }

        public int lstGTSeconds = 0;

        public string lastTickMsg = string.Empty;

        public void drawLine(Vector2 v1, Vector2 v2, int lineWidth, Color color)
        {
            float angle = (float)Math.Atan2(v2.Y - v1.Y, v2.X - v1.X);
            float length = Vector2.Distance(v1, v2);

            spriteBatch.Draw(Content.Load<Texture2D>("Textures/white"), v1, null, color,
                                   angle, Vector2.Zero, new Vector2(length, lineWidth),
                                   SpriteEffects.None, 0);
        }

        public void DrawRectangle(Rectangle rectangle, Color color)
        {
            Vector2 tl = new Vector2(rectangle.X, rectangle.Y);
            Vector2 tr = new Vector2(rectangle.X + rectangle.Width, rectangle.Y);

            Vector2 bl = new Vector2(rectangle.X, rectangle.Y + rectangle.Height);
            Vector2 br = new Vector2(rectangle.X + rectangle.Width, rectangle.Y + rectangle.Height);

            // Draw the lines
            drawLine(tl, tr, 1, color);
            drawLine(tr, br, 1, color);
            drawLine(br, bl, 1, color);
            drawLine(bl, tl, 1, color);
            
        }

        public void ShowPopUpMessage(PopMsg msg)
        {
            PopUpMessages.Add(msg);
        }        
    }
    public class PopMsg
    {
        public string message { get; set; }
        public TimeSpan fired = DateTime.Now.TimeOfDay;
        public TimeSpan duration = new TimeSpan(0, 0, 0, 1, 0);
        public bool FadeOut { get { return (duration - (DateTime.Now.TimeOfDay - fired)) < TimeSpan.Zero; } }
        public float opacity = 1;
        public float fade = .05f;
        public Vector2 position { get; set; }
        public Color Color = Color.White;
    }
}
